// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QFile>
#include "clientthread.h"

#include <QRandomGenerator>

#include <stdlib.h>
//#include <QTcpSocket>

//! [0]
ClientThread::ClientThread(QObject *parent)
    : QThread(parent)
{
    qDebug()<<"ClientThread constructed";
    qDebug()<< QString("ClientThread")<< QThread::currentThreadId()<< this; //this输出为ClientThread(0x7eee050f60)。
//    if(pba == nullptr)
//        qDebug()<<QString("err: pba==nullptr");


    bin_sta= 1; //初始化

    fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
             << tr("You've got to think about tomorrow.")
             << tr("You will be surprised by a loud noise.")
             << tr("You will feel hungry again in another hour.")
             << tr("You might have mail.")
             << tr("You cannot kill time without injuring eternity.")
             << tr("Computers are not intelligent. They only think they are.");
//    socket= new QTcpSocket(this);
//    /*在发射者中建立关联：编译提示：
//    qt.core.qobject.connect: QObject::connect: Cannot connect FortuneServer::error(QString) to (nullptr)::show_err(QString)
//    是因为在dialog.h中定义server时，按默认值，即parent=nullptr。
//    但实测ok。
//    虽然可以使用.setParent(this)设置，但构造函数时，parent是nullptr。
//    */
//    //QAbstractSocket::connect(this, SIGNAL(error(QString)), parent, SLOT(show_err(QString)));

//    //connect(socket, &QIODevice::readyRead, this, &ClientThread::readFortune);      //都是QTcpSocket下的信号，怎么有QIODevice::readyRead()和QAbstractSocket::errorOccured()的区别呢？一看帮助文件就明白。
////! [2] //! [4]
//    connect(socket, &QAbstractSocket::errorOccurred, this, &ClientThread::displayError);
//    connect(socket, &QTcpSocket::connected, this, &ClientThread::connectX);    //QTcpSocket::connected OK.
//    connect(socket, &QTcpSocket::disconnected, this, &ClientThread::disconnect);




    //! [4]
}

ClientThread::~ClientThread()
{
    qDebug()<< "ClientThread destroy";
}

void ClientThread::setIP(QString ip)
{
    str_ip_server= ip;
}

void ClientThread::setPort(quint16 port)
{
    port_server= port;
}

/*执行线程
*/
void ClientThread::startX(void)
{
    //connect(socket, &QAbstractSocket::errorOccurred, this, &ClientThread::displayError);
    qDebug()<< QString("ClientThread2")<< QThread::currentThreadId();
    this->start();
}


/*线程函数:
 *      连接主机成功                         数据信息解析正常              收齐指定长度的数据            发送数据确认             服务器断开
  *Idle ----------->SendPwd --> WaitInfo -----------------> WaitData ------------------> RecvOk -------------> WaitDis -----------> DisOk (退出线程)
  *在线程运行时，可能进入Error，此时会退出线程。
*/
void ClientThread::run()
{
    qint32 data_len;            //程序的字节长度。
    qint32 tot_len, cur_len;             //当前包的长度。
    QByteArray ba_to_host;
    QTcpSocket* socket;
    QString file_name;

    bin_sta= 1;
    ba_bin.clear();
    socket= new QTcpSocket(this);

    //connect(socket, &QTcpSocket::disconnected, this, &ClientThread::disconnect);

    //初始状态：连接服务器，并等待连接结果：
    sta= Sta_Client::Idle;

    socket->connectToHost(str_ip_server, port_server);
    if(false == socket->waitForConnected(3*1000)){
        qDebug()<<"err&exit: connectToHost()"<< str_ip_server<< port_server;;

        return;
    }
    else{
        qDebug()<<"connected to host"<< str_ip_server<< port_server;
    }

    qDebug()<<"clientthread running"<< QThread::currentThreadId();
    sta = Sta_Client::SendPwd;

    while(1){
        if(0){
        }
        else if(sta == Sta_Client::Idle){       //作废。
            qDebug()<<"connetting to Host:";

            socket->abort();

            if((!str_ip_server.isEmpty())&&(0 != port_server)){
                qDebug()<<str_ip_server<< port_server;
                socket->connectToHost(str_ip_server, port_server);
                sta= Sta_Client::WaitCon;
            }
            else{
                sta= Sta_Client::Error;
            }
        }
        else if(sta == Sta_Client::WaitCon){
            //QThread::msleep(100);
            qDebug()<<"waiting for connect";
              //QThread::msleep(2*1000);
              sta= Sta_Client::SendPwd;
        }
        else if(sta == Sta_Client::SendPwd){    //发送连接密码。
            ba_to_host.clear();

            ba_to_host.append('L');
            ba_to_host.append('J');
            ba_to_host.append('m');
            ba_to_host.append('a');
            ba_to_host.append('o');
            ba_to_host.append('k');

            socket->write(ba_to_host);
            tot_len= 0;
            sta= Sta_Client::WaitInfo;

            qDebug()<<"sent pwd ok";
        }
        else if(sta == Sta_Client::WaitInfo){   //等待服务器发过来文件信息。
            if(false == socket->waitForReadyRead(3*1000)){
                //
                emit error(QString("err: wait info"));
                qDebug()<<"err: wait info";

                break;
            }
            else{
                QByteArray ba;
                QString head;
                QString len;

                QDataStream in(&ba, QIODevice::ReadOnly);

                ba= socket->readAll();
                in.startTransaction();
                in>> head;
                in>> len;
                in>> file_name;
                //in.abortTransaction()
                qDebug()<<"RECV:"<< head<< len<<file_name;


                //if(head== QString("XX")){
                if(head == QString("XX")){
                //包头：正确包头。
                    data_len= len.toInt();
                    bin_name= file_name;
                    ba_to_host.clear();

                    ba_to_host.append('A');
                    ba_to_host.append('C');
                    ba_to_host.append('K');

                    socket->write(ba_to_host);
                    sta= Sta_Client::WaitData;
                    //data_len= 162352;

                    qDebug()<< "--ACK-->host requisting data:"<< data_len;
                }
            }
        }
        else if(sta == Sta_Client::WaitData){   //接收服务器发过来的数据。
            /*接收数据:
             * a. 在指定时间内没有收到指定长度的数据。
             * b.
            */
            QByteArray ba;


            while(1){
                if(true == socket->waitForReadyRead(200)){
                    ba= socket->readAll();
                    tot_len+= ba.size();
                    ba_bin+= ba;    //ba_bin是最后的数据。

                    qDebug()<< ba.size()<< ba_bin.size();

                    if(tot_len == data_len){
                        sta= Sta_Client::RecvOk;
                        qDebug()<< "data recv ok,len="<< tot_len;

                        break;
                    }
                    else if(tot_len> data_len){
                        emit error(QString("data len ovr"));
                        qDebug()<< "data len ovr";

                        break;
                    }
                }
                else{
                    qDebug()<< "flase: waitForReadyRead()";
                    break;
                }

                //QThread::msleep(100);   //QQ认为加入延时了，理解对吗？

                //
            }
        }
        else if(sta == Sta_Client::RecvOk){     //数据全部接收完成。
            QThread::msleep(1*1000);

            ba_to_host.clear();

            ba_to_host.append('O');
            ba_to_host.append('K');

            socket->write(ba_to_host);
            sta =Sta_Client::WaitDis;

            qDebug()<<"--OK-->host";
        }
        else if(sta == Sta_Client::WaitDis){    //等待服务器的端口（client不主动断开）
            if(true == socket->waitForDisconnected(3*1000)){
                //将数据ba_bin存入指定文件中
                bin_sta= 0; //传输完成：成功
                emit TransOk(file_name);

                qDebug()<< QString("host disconnected")<< file_name;
            }
            else{
                bin_sta= 2; //传输完成：失败。
                emit error(QString("err: disconnected"));

                qDebug()<< "err: disconnected";
            }

            break;
        }
        else if(sta == Sta_Client::DisOk){      //已断开
            qDebug()<<"host has disconnected";
            break;
        }
        else if(sta == Sta_Client::Error){      //发生了错误
            qDebug()<< "err to exit";
            break;
        }
    }//end of while().

    qDebug()<<"client thread exit";
}

QByteArray ClientThread::get_ba_bin()
{
    qDebug()<<QString("ClientThread's ba_bin len=")<< ba_bin.size();
    return ba_bin;
}

QString ClientThread::get_bin_name()
{
    return bin_name;
}


//! [0]

//! [1]
//void ClientThread::incomingConnection(qintptr socketDescriptor)
//{
//    QString fortune = fortunes.at(QRandomGenerator::global()->bounded(fortunes.size()));
//    FortuneThread *thread = new FortuneThread(socketDescriptor, fortune, this);     //每建立一次连接，传入一个新的字符串。谁来释放呢？
//    connect(thread, &FortuneThread::finished, thread, &FortuneThread::deleteLater); //不能自己处理吗？不能，因为处理的是实例，不是类。

//    connect(thread, &FortuneThread::error_str, this, &FortuneServer::error_to_gui);
//    /*finished信号，就可以删除线程自己吗（对象/实例）。
//    */
//    thread->start();
//}

void ClientThread::error_to_gui(QString err)
{

    qDebug()<<"info from thread:"<<(quint64)sender()<< err;

    emit error(err);    //与error()关联的slot是

//    tcpSocket->abort();     //Aborts the current connection and resets the socket. Unlike disconnectFromHost(), this function immediately closes the socket, discarding any pending data in the write buffer.
////! [7]                     //->disconnectFromHost(): Attempts to close the socket.
//    tcpSocket->connectToHost(hostCombo->currentText(),
//                             portLineEdit->text().toInt());
}


/*连接或通信时的
*/
void ClientThread::displayError(QAbstractSocket::SocketError)
{

    sta= Sta_Client::Error;
}

void ClientThread::connectX()
{
    qDebug()<<"connect ok XXX";

    sta= Sta_Client::SendPwd;
}

void ClientThread::disconnect()
{
    sta= Sta_Client::DisOk;
    qDebug()<<"Host disconnected";
}
//! [1]
